/*
 * This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 * for more details.
 * 
 * You should have received a copy of the GNU General Public License along 
 * with this program; if not, write to the Free Software Foundation, Inc., 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <QFile>
#include <QFileInfo>
#include <QStringList>
#include <QHttp>
#include <QHttpResponseHeader>
#include <QUrl>
#include <QDir>
#include <QSettings>
#include <QCryptographicHash>
#include <QtConcurrentRun>
#include "chan.h"
#include "log.h"
#include "board.h"
#include "thread.h"
#include "post.h"
#include "chanmanager.h"
#include "keymap.h"
#include "analyzers/extractor.h"
#include "filterlist.h"
#include "coding/codingmanager.h"
#include "watermarking/watermarkgeneratorfactory.h"

namespace Wishmaster
{
	Chan::Chan(QString const& host, ChanAgent* agent, ChanManager* manager) : QObject(),
		m_host(host),
		m_threadStorage(NULL),
		m_agent(agent),
		m_keymap(NULL),
		m_chanmanager(manager)
	{
		if(manager)
		{
			m_taskhub = manager->taskhub();
			if(m_taskhub)
				m_agent->setTaskhub(m_taskhub);
		}
	}

	Chan::~Chan()
	{
		for(std::vector<Board*>::iterator it = m_boards.begin(); it != m_boards.end(); ++it)
		{
			delete (*it);
		}
		m_boards.clear();
		if(m_keymap)
			delete m_keymap;
	}

	QStringList Chan::getBoards()
	{
		QStringList list;
		foreach(Board* b, m_boards)
		{
			list.append(b->name());
		}
		return list;
	}

	QStringList Chan::getBoardAliases()
	{
		QStringList list;
		foreach(Board* b, m_boards)
		{
			list.append(b->alias());
		}
		return list;
	}

	void Chan::addBoard(Board* board)
	{
		if(!board)
			return;
		m_boards.push_back(board);
		// TODO check for double-adding
	}

	Board* Chan::board(QString const& boardId)
	{
		foreach(Board* b, m_boards)
		{
			if(b->name() == boardId)
				return b;
		}

		return NULL;
	}

	Board* Chan::board(int boardNumber)
	{
		if(m_boards.size() <= (unsigned int)boardNumber || boardNumber < 0)
			return NULL;
		return m_boards.at(boardNumber);
	}

	int Chan::boardsCount() const
	{
		return m_boards.size();
	}

	QString const& Chan::getHost()
	{
		return m_host;
	}

	QString Chan::name() const
	{
		return m_host;
	}

	void Chan::setThreadStorage(ThreadStorage* threadstorage)
	{
		m_threadStorage = threadstorage;
		for(std::vector<Board*>::iterator it = m_boards.begin(); it != m_boards.end(); ++it)
		{
			Board* b = static_cast<Board*>(*it);
			b->setThreadStorage(threadstorage);
		}
	}

	ThreadStorage* Chan::threadStorage()
	{
		return m_threadStorage;
	}

	void Chan::load()
	{
		for(std::vector<Board*>::iterator it = m_boards.begin(); it != m_boards.end(); ++it)
		{
			Board* b = static_cast<Board*>(*it);
			b->load();
		}
	}

	void Chan::save()
	{
		if(threadStorage())
		{
			for(std::vector<Board*>::iterator it = m_boards.begin(); it != m_boards.end(); ++it)
			{
				Board* b = static_cast<Board*>(*it);
				b->save();
				b->saveSettings();
			}
		}
	}

	void Chan::swap()
	{
		QDateTime current = QDateTime::currentDateTime();
		QSettings settings;
		int interval = settings.value("threadstorage/swapping_interval", 900).toInt();
		for(std::vector<Board*>::iterator it = m_boards.begin(); it != m_boards.end(); ++it)
		{
			Board* b = static_cast<Board*>(*it);
			b->swap(current, interval);
		}
	}

	void Chan::setKeymap(Keymap* k)
	{
		m_keymap = k;
	}

	Keymap* Chan::keymap()
	{
		return m_keymap;
	}
	
	void Chan::setExtractor(Extractor* extractor)
	{
		m_extractor = extractor;
	}
	
	Extractor* Chan::extractor()
	{
		return m_extractor;
	}


	void Chan::collectGarbage()
	{
		for(std::vector<Board*>::iterator it = m_boards.begin(); it != m_boards.end(); ++it)
		{
			(*it)->collectGarbage();
		}
	}

	QByteArray Chan::makePostHid(const QString& board, unsigned long threadId, unsigned long postId)
	{
		return (m_host + board + QString::number(threadId) + '/' + QString::number(postId)).toUtf8();
	}

	BoardConstraints Chan::constraints(const QString& boardname)
	{
		if(boardname.isNull())
			return m_constraints;
		Board* b = board(boardname);
		if(b)
			return b->constraints();
		return m_constraints;
	}

	void Chan::setConstraints(const BoardConstraints& constraints)
	{
		m_constraints = constraints;
	}

	bool Chan::sageCheckbox()
	{
		return false;
	}

	QImage Chan::icon() const
	{
		return m_icon;
	}

	void Chan::setIcon(const QImage& i)
	{
		m_icon = i;
	}
}

